﻿using OxyPlot.Axes;
using OxyPlot.Legends;
using OxyPlot.Series;
using OxyPlot;
using static NetMQ.NetMQSelector;

namespace Ops.Host.App.ViewModels;

public sealed class KibanaViewModel : ObservableObject, IViewModel, IDisposable
{
    private readonly CancellationTokenSource _cts = new();

    private readonly DeviceInfoManager _deviceInfoManager;
    private readonly DeviceHealthManager _deviceHealthManager;

    /// <summary>
    /// 定时器处理对象
    /// </summary>
    public EventHandler? TimerHandler { get; set; }

    public KibanaViewModel(
        DeviceInfoManager deviceInfoManager,
        DeviceHealthManager deviceHealthManager)
    {
        _deviceInfoManager = deviceInfoManager;
        _deviceHealthManager = deviceHealthManager;

        Init();
    }

    void Init()
    {
        var deviceInfos = _deviceInfoManager.GetAll();
        foreach (var deviceInfo in deviceInfos)
        {
            DeviceSourceList.Add(new KibanaModel
            {
                Line = deviceInfo.Schema.Line,
                Station = deviceInfo.Schema.Station,
                ConnectedState = false,
            });
        }

        // 连接状态检测，定时器可考虑与 DispatcherTimer 有什么差异
        _deviceHealthManager.Check();
        _ = Task.Factory.StartNew(async () =>
        {
            while (!_cts.IsCancellationRequested)
            {
                await Task.Delay(2000);
                ChangeDeviceConnState();
            }

        }, default, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());

        // 初始化能耗图
        InitEnergyChart();

        // 监听消息
        _ = Task.Factory.StartNew(async () =>
        {
            var random = new Random();
            while (!_cts.IsCancellationRequested)
            {
                while (!_cts.IsCancellationRequested)
                {
                    var (ok, msg) = await MessageTaskQueueManager.Default.WaitDequeueAsync();
                    if (!ok)
                    {
                        break;
                    }

                    switch (msg!.Code)
                    {
                        case MessageClassify.Alarm:
                            AddAlarmMessage(msg);
                            break;
                        case MessageClassify.SpotCheck:
                            AddSpotCheckMessage(msg);
                            break;
                        case MessageClassify.Marking:
                            AddMarkingMessage(msg);
                            break;
                        case MessageClassify.CardSwiping:
                            AddCardSwipingMessage(msg);
                            break;
                        case MessageClassify.Energy:
                            AddEnergyMessage(msg);
                            break;
                        default:
                            break;
                    }
                }
            }

        }, default, TaskCreationOptions.LongRunning, TaskScheduler.FromCurrentSynchronizationContext());
    }

    #region 绑定属性

    private ObservableCollection<KibanaModel> _deviceSourceList = new();

    public ObservableCollection<KibanaModel> DeviceSourceList
    {
        get => _deviceSourceList;
        set => SetProperty(ref _deviceSourceList, value);
    }

    #region 警报

    private ObservableCollection<AlarmModel> _alarmSourceList = new();

    public ObservableCollection<AlarmModel> AlarmSourceList
    {
        get => _alarmSourceList;
        set => SetProperty(ref _alarmSourceList, value);
    }

    private void AddAlarmMessage(Message msg)
    {
        // 超过指定数量，移除最后一条数据。
        if (AlarmSourceList.Count >= 32)
        {
            AlarmSourceList.RemoveAt(AlarmSourceList.Count - 1);
        }

        // 插入数据到起始位置（UI 上倒序显示）。
        AlarmSourceList.Insert(0, new()
        {
            Station = msg.Station,
            Name = msg.Name,
        });
    }

    #endregion

    #region 刷卡

    private ObservableCollection<CardSwipingModel> _cardSwipingModelSourceList = new();

    public ObservableCollection<CardSwipingModel> CardSwipingModelSourceList
    {
        get => _cardSwipingModelSourceList;
        set => SetProperty(ref _cardSwipingModelSourceList, value);
    }

    private void AddCardSwipingMessage(Message msg)
    {
        // 超过指定数量，移除最后一条数据。
        if (CardSwipingModelSourceList.Count >= 32)
        {
            CardSwipingModelSourceList.RemoveAt(CardSwipingModelSourceList.Count - 1);
        }

        // 插入数据到起始位置（UI 上倒序显示）。
        var (cardDeviceName, cardDeviceNo, owner) = ((string?, string?, string?))msg.Value!;
        CardSwipingModelSourceList.Insert(0, new()
        {
            Station = msg.Station,
            CardNo = msg.Name,
            Owner = owner,
            CardDeviceName = cardDeviceName,
            CardDeviceNo = cardDeviceNo,
        });
    }

    #endregion

    #region 打标

    private ObservableCollection<MarkingModel> _markingSourceList = new();

    public ObservableCollection<MarkingModel> MarkingSourceList
    {
        get => _markingSourceList;
        set => SetProperty(ref _markingSourceList, value);
    }

    private void AddMarkingMessage(Message msg)
    {
        // 超过指定数量，移除最后一条数据。
        if (MarkingSourceList.Count >= 32)
        {
            MarkingSourceList.RemoveAt(MarkingSourceList.Count - 1);
        }

        // 插入数据到起始位置（UI 上倒序显示）。
        var sn = (string)msg.Value!;
        MarkingSourceList.Insert(0, new()
        {
            SN = sn,
            MarkingTime = DateTime.Now,
        });
    }

    #endregion

    #region 点检

    private ObservableCollection<SpotCheckModel> _spotChecskSourceList = new();

    public ObservableCollection<SpotCheckModel> SpotCheckSourceList
    {
        get => _spotChecskSourceList;
        set => SetProperty(ref _spotChecskSourceList, value);
    }

    private void AddSpotCheckMessage(Message msg)
    {
        // 超过指定数量，移除最后一条数据。
        if (SpotCheckSourceList.Count >= 32)
        {
            SpotCheckSourceList.RemoveAt(SpotCheckSourceList.Count - 1);
        }

        // 插入数据到起始位置（UI 上倒序显示）。
        var (item, pass) = ((string?, bool))msg.Value!;
        SpotCheckSourceList.Insert(0, new()
        {
            Station = msg.Station,
            Tooling = msg.Name,
            Item = item,
            IsPass = pass!,
        });
    }

    #endregion

    #region 能耗

    public PlotModel EnergyPlotModel { get; } = new()
    {
        TitleFontSize = 14,
        TitleFontWeight = OxyPlot.FontWeights.Normal,
        TitleColor = OxyColors.Green,
        Title = "能耗累计数据",
    };

    private void AddEnergyMessage(Message msg)
    {
        var series = (LineSeries?)EnergyPlotModel.Series.FirstOrDefault(s => s.Title == msg.Name);
        if (series == null)
        {
            return;
        }

        if (series.Points.Count >= 16)
        {
            series.Points.RemoveAt(0);
        }
        
        var energy = Convert.ToDouble(msg.Value!);
        series.Points.Add(new DataPoint(DateTimeAxis.ToDouble(DateTime.Now), energy));
        EnergyPlotModel.InvalidatePlot(true); // 实时更新数据
    }

    private void InitEnergyChart()
    {
        // X轴
        var dateAxis = new DateTimeAxis()
        {
            MajorGridlineStyle = LineStyle.Automatic,
            MinorGridlineStyle = LineStyle.Dot,
            StringFormat = "MM/dd HH:mm", // 日期格式
            Angle = 15,
            //IntervalLength = 60,
            IsZoomEnabled = false,
            IsPanEnabled = false,
        };
        EnergyPlotModel.Axes.Add(dateAxis);

        // Y轴
        var valueAxis = new LinearAxis()
        {
            MajorGridlineStyle = LineStyle.Solid,
            MinorGridlineStyle = LineStyle.Dot,
            IntervalLength = 20,
            //Angle = 20,
            IsZoomEnabled = false,
            IsPanEnabled = false,
        };
        EnergyPlotModel.Axes.Add(valueAxis);

        // 添加 Legend
        var legend = new Legend
        {
            LegendPlacement = LegendPlacement.Outside,
        };
        EnergyPlotModel.Legends.Add(legend);

        // 添加数据曲线
        string[] lineNames = { "有功", "无功" };
        foreach (string lineName in lineNames)
        {
            LineSeries series = new()
            {
                StrokeThickness = 2,
                MarkerSize = 3,
                MarkerType = MarkerType.Circle,
                Title = lineName,
            };

            EnergyPlotModel.Series.Add(series);
        }
    }

    #endregion

    #endregion

    #region privates

    private void ChangeDeviceConnState()
    {
        foreach (var device in DeviceSourceList)
        {
            var state = _deviceHealthManager.CanConnect(device.Line, device.Station);
            if (device.ConnectedState != state)
            {
                device.ConnectedState = state;
            }
        }
    }

    #endregion

    public void Dispose()
    {
        _cts.Cancel();
    }
}

public sealed class AlarmModel
{
    public string? Station { get; set; }

    public string? Name { get; set; }

    public DateTime CreateTime { get; set; } = DateTime.Now;
}

public sealed class SpotCheckModel
{
    public string? Station { get; set; }

    public string? Tooling { get; set; }

    public string? Item { get; set; }

    public bool IsPass { get; set; }

    public DateTime CreateTime { get; set; } = DateTime.Now;
}

public sealed class CardSwipingModel
{
    public string? Station { get; set; }

    public string? CardNo { get; set; }

    public string? Owner { get; set; }

    public string? CardDeviceName { get; set; }

    public string? CardDeviceNo { get; set; }

    public DateTime CreateTime { get; set; } = DateTime.Now;
}

public sealed class MarkingModel
{
    public string? SN { get; set; }

    public DateTime MarkingTime { get; set; }
}
